package com.topisv.tms.utils.aop;

import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(2)
@Component
//@Aspect
public class PerfInterceptor {

	private Logger logger = LoggerFactory.getLogger(getClass());
	private static ConcurrentHashMap<String, MethodStats> methodStats = new ConcurrentHashMap<String, MethodStats>();
	private static long statLogFrequency = 10;
	private static long methodWarningThreshold = 3000;

	//@Around("execution(* com.topisv.tms.service..*.*(..))")
	public Object invoke(ProceedingJoinPoint method) throws Throwable {
		long start = System.currentTimeMillis();
		try {
			return method.proceed();
		} finally {
			updateStats(method.getSignature().toShortString(), (System.currentTimeMillis() - start));
		}
	}

	private void updateStats(String methodName, long elapsedTime) {
		MethodStats stats = methodStats.get(methodName);
		if (stats == null) {
			stats = new MethodStats(methodName);
			methodStats.put(methodName, stats);
		}
		stats.count++;
		stats.totalTime += elapsedTime;
		if (elapsedTime > stats.maxTime) {
			stats.maxTime = elapsedTime;
		}

		if (elapsedTime > methodWarningThreshold) {
			logger.warn("{}, count = {}, elapsedTime = {}, maxTime = {}", methodName, stats.count, elapsedTime, stats.maxTime);
		}

		if (stats.count % statLogFrequency == 0) {
			long avgTime = stats.totalTime / stats.count;
			long runningAvg = (stats.totalTime - stats.lastTotalTime) / statLogFrequency;
			logger.debug("{}, count = {}, elapsedTime = {}, avgTime = {}, runningAvg = {}, maxTime = {}", methodName, stats.count, elapsedTime, avgTime, runningAvg, stats.maxTime);
			// reset the last total time
			stats.lastTotalTime = stats.totalTime;
		}
	}

	class MethodStats {
		public String methodName;//调用的方法名
		public long count;//调用次数
		public long totalTime;//总时长
		public long lastTotalTime;//上一次的总时长
		public long maxTime;//最大时长

		public MethodStats(String methodName) {
			this.methodName = methodName;
		}
	}
}